package com.xc.common.filter;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import com.ag.utils.MdcUtil;
import com.ag.utils.RequestUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xc.utils.Loggers;

/**
 * 
 * title: HttpTraceLogFilter.java 一次请求的生命周期的日志记录
 *
 * @author rplees
 * @email rplees.i.ly@gmail.com
 * @version 1.0
 * @created Apr 21, 2020 5:36:38 PM
 */
public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered {
	public String[] ignorePath = new String[] {
			/** Swagger */
			"/error**", "/v2/api-docs**", "/swagger-resources**", "/swagger-resources/**", "/configuration/**" };
	public HttpTraceLogFilter() {
	}
	
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		String traceId = request.getHeader(MdcUtil.TRACE_ID);
        if (traceId == null) {
            traceId = MdcUtil.getTraceId();
        }

        MDC.put(MdcUtil.TRACE_ID, traceId);
        
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
		if (isNotTraceLogRequestValid(requestWrapper, responseWrapper)) {
			filterChain.doFilter(requestWrapper, responseWrapper);
			responseWrapper.copyBodyToResponse();
			updateResponse(responseWrapper);
			return;
		}
		
		long startTime = System.currentTimeMillis();
		try {
			filterChain.doFilter(requestWrapper, responseWrapper);
		} finally {
			if (!Lists.newArrayList("multipart/form-data")
					.contains(StringUtils.lowerCase(responseWrapper.getContentType()))) {
				Map<String, Object> ret = Maps.newLinkedHashMap();
				ret.put("请求信息", requestWrapper.getRequestURI() + ">>>" + request.getMethod() + "<<<");
				ret.put("逻辑耗时", (System.currentTimeMillis() - startTime) + "毫秒");

				String method = request.getMethod();
				if ("GET".equals(method)) {
					ret.put("参数", prettyString(JSON.toJSONString(requestWrapper.getParameterMap())));
				} else {
					ret.put("参数", prettyString(new String(requestWrapper.getContentAsByteArray())));
				}

				Object resp = null;
				String responseString = new String(responseWrapper.getContentAsByteArray());

				if (resp == null) {
					resp = prettyString(responseString);
				}
				ret.put("返回信息", resp);

				ret.put("请求头", RequestUtils.getRequestHeaders(requestWrapper));
//				if (StringUtils.containsIgnoreCase(responseWrapper.getContentType(),
//						MediaType.APPLICATION_JSON_VALUE)) {
					Loggers.VISIT.info(JSON.toJSONString(ret));
//				}
			}
			responseWrapper.copyBodyToResponse();
		}
		updateResponse(responseWrapper);
	}

	private Object prettyString(String s) {
		try {
			return JSON.parse(s);
		} catch (Exception ex) {
		}

		return s;
	}

	private boolean isNotTraceLogRequestValid(HttpServletRequest request, HttpServletResponse response) {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		// 如果是POST请求 并且不是文件上传类的, 则替换
		if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) {
			if (ServletFileUpload.isMultipartContent(httpServletRequest)) {
				return true;
			}
		}

		String requestURI = request.getRequestURI();
		for (String string : ignorePath) {
			if(StringUtils.startsWith(string, requestURI)) {
				return true;
			}
		}
		
		return false;
	}

	/**
	 * 还原返回
	 *
	 * @param response
	 * @throws IOException
	 */
	private void updateResponse(HttpServletResponse response) throws IOException {
		ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response,
				ContentCachingResponseWrapper.class);
		Objects.requireNonNull(responseWrapper).copyBodyToResponse();
	}

	public int getOrder() {
		return Ordered.HIGHEST_PRECEDENCE;
	}
}
